/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package checkInputType;

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;

import generateAndLoadClasses.*;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonErrorNode;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

/**
 *
 * @author daniel
 */


public class GetInputType {
    public static TryReturn tryType(String grammar,String type,String string) throws IOException, NoSuchFieldException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        TryReturn ret = new  TryReturn();
        ANTLRStringStream fs = new ANTLRStringStream(string);
        GrammarClassLoader gcl = new GrammarClassLoader();
        Object lex = gcl.loadClass(/*"grammar."+*/grammar+"TreePGLexer").getConstructor(CharStream.class).newInstance(fs);
			
        TokenRewriteStream tokens = new TokenRewriteStream((Lexer)lex);
			
        Object p = gcl.loadClass(/*"grammar."+*/grammar+"TreePGParser").getConstructor(org.antlr.runtime.TokenStream.class).newInstance(tokens);
        
        Method method = null;
        try {
            // p - parserul incarcat dinamic
        	// start - regula de start 
        	method = p.getClass().getMethod(type);
            
            PrintStream oldOut = System.out; 
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            System.setErr(new PrintStream(out));
            
            PrintStream oldErr = System.err; 
            ByteArrayOutputStream err = new ByteArrayOutputStream();
            System.setErr(new PrintStream(err));

            ParserRuleReturnScope rez = (ParserRuleReturnScope)method.invoke(p);
            System.setOut(oldOut);
            System.setErr(oldErr);
            
            // accesarea arborelui construit de parser
            Field appR = p.getClass().getDeclaredField("tree");
            appR.setAccessible(true);
            //ret - incapsuleaza daca inputul a fost parsat cu succes si arborele generat
            ret.setTree( (gettree.Tree)appR.get(p));
            
            if (rez==null){
                ret.setMatched(false);
                return ret;
            }
            else {
            	//System.out.println(err.size());
                if (err.size() > 0 ){
                	//System.out.println(err);
                    ret.setMatched(false);
                    return ret;
                    //return false ;
                }
               // printTree((CommonTree)rez.getTree(), 1);
                String s =getTreeString((CommonTree)rez.getTree(), 1);
                if (((Tree) rez.getTree()).getChildCount() > 0 || !((Tree) rez.getTree()).getText().trim().equals("")) {
                  //return checkTreeForError((Tree)rez.getTree()) &&  (s.trim().startsWith(string.trim().substring(0, 1)) && s.trim().endsWith(string.trim().substring(string.length()-1)));
                  ret.setMatched(checkTreeForError((Tree)rez.getTree()) &&  (s.trim().startsWith(string.trim().substring(0, 1)) && s.trim().endsWith(string.trim().substring(string.length()-1))));
                  return ret;
                }
                else{
                    ret.setMatched(false);
                    return ret;
                    //return false;
                }
                
            }
            
                        //{
                //if (rez.getTree() instanceof CommonErrorNode)
                //    return false;
               // 
               // else
                //    return true;
            
        } catch (IllegalAccessException ex) {
            Logger.getLogger(GetInputType.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(GetInputType.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(GetInputType.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException e) {
          e.printStackTrace();
        } catch (NoSuchMethodException e) {
                    e.printStackTrace();

        }        
        ret.setMatched(false);
        return ret;
        //return false;
    }
    
    public static boolean checkTreeForError(Tree t) {
		if (t instanceof CommonErrorNode)
                                return false;
                if ( t != null ) {
			for ( int i = 0; i < t.getChildCount(); i++ ) {
                            if (t.getChild(i) instanceof CommonErrorNode)
                                return false;
                            else
				return checkTreeForError(t.getChild(i));
			}
		}
                return true;
	}
    
    public static ReturnAst getAst(String grammar,String type,String string) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException, NoSuchFieldException{
    	ReturnAst ret = new ReturnAst();
//    	ANTLRStringStream fs = new ANTLRStringStream(string);
//        GrammarClassLoader gcl = new GrammarClassLoader();
//        Object lex = gcl.loadClass(/*"grammar."+*/grammar+"MLexer").getConstructor(CharStream.class).newInstance(fs);
//        TokenRewriteStream tokens = new TokenRewriteStream((Lexer)lex);
//        Object p = gcl.loadClass(/*"grammar."+*/grammar+"MParser").getConstructor(org.antlr.runtime.TokenStream.class).newInstance(tokens);
 //       Method method = null;
//        method = p.getClass().getMethod(type);
//        ParserRuleReturnScope rez = (ParserRuleReturnScope)method.invoke(p);
//        ret.setTree((Tree)rez.getTree());
//        Field appR = p.getClass().getDeclaredField("rules");
//        appR.setAccessible(true);
 //       ret.setApprulesArrayList( (ArrayList<String>)appR.get(p));
        return ret;
    }
    
    
    public static void printTree(CommonTree t, int indent) {
	System.out.println(t.getText());	
        if ( t != null ) {
			StringBuffer sb = new StringBuffer(indent);
			for ( int i = 0; i < indent; i++ )
				sb = sb.append("   ");
			for ( int i = 0; i < t.getChildCount(); i++ ) {
				System.out.println(sb.toString() + t.getChild(i).toString());
				printTree((CommonTree)t.getChild(i), indent+1);
			}
		}
	}
    public static String getTreeString(CommonTree t, int indent) {
	StringBuffer  s = new StringBuffer();
        if (t.getText()!=null)
            s.append(t.getText());
        if ( t != null ) {
			StringBuffer sb = new StringBuffer(indent);
			for ( int i = 0; i < indent; i++ )
				sb = sb.append(" ");
			for ( int i = 0; i < t.getChildCount(); i++ ) {
				s.append((sb.toString() + t.getChild(i).toString()));
				printTree((CommonTree)t.getChild(i), indent+1);
			}
		}
        return s.toString();
    }
    
    public static void main (String[]a) throws Exception{
        System.out.println(tryType("impM", "aExp"," a+b+c"));
        
       // printTree(tree, 0);
        //impParser.stmt_return r = (impParser.stmt_return)p.stmt();
    }
    
    
}
